This is the MB1 semester R Project.
Fig. Map showing the mining operation with in the indigenous reserve, which is the study site of this R project. 
Loading libraries
Installing and loading R libraries for the following processing and visualization.
if(!require(devtools)) install.packages("devtools", repos = "http://cran.us.r-project.org")
if(!require(patchwork)) install.packages("patchwork", repos = "http://cran.us.r-project.org")
if(!require(sp)) install.packages("sp", repos = "http://cran.us.r-project.org")
if(!require(sf)) install.packages("sf", repos = "http://cran.us.r-project.org")
if(!require(rgdal)) install.packages("rgdal", repos = "http://cran.us.r-project.org")
if(!require(ggplot2)) install.packages("ggplot2", repos = "http://cran.us.r-project.org")
if(!require(reshape2)) install.packages("reshape2", repos = "http://cran.us.r-project.org")
if(!require(data.table)) install.packages("data.table", repos = "http://cran.us.r-project.org")
if(!require(ggthemes)) install.packages("ggthemes", repos = "http://cran.us.r-project.org")
if(!require(ggnewscale)) install.packages("ggnewscale", repos = "http://cran.us.r-project.org")
if(!require(tidyverse)) install.packages("tidyverse", repos = "http://cran.us.r-project.org")
if(!require(rasterVis)) install.packages("rasterVis", repos = "http://cran.us.r-project.org")
if(!require(mapview)) install.packages("mapview", repos = "http://cran.us.r-project.org")
if(!require(RStoolbox)) install.packages("RStoolbox", repos = "http://cran.us.r-project.org")
if(!require(glcm)) install.packages("rgee", repos = "http://cran.us.r-project.org")
if(!require(rgee)) install.packages("rgee", repos = "http://cran.us.r-project.org")
if(!require(leaflet)) install.packages("leaflet", repos = "http://cran.us.r-project.org")
if(!require(dplyr)) install.packages("dplyr", repos = "http://cran.us.r-project.org")
User-defined parameter
pic_save = FALSE #TRUE #please change the parameter to TRUE if outputs wished to be downloaded
Task 1: Landsat 8 scene pre-processing
Landsat 8 scenes at the region of interest have been downloaded from USGS. Here we set up the directory and check the existence of the tiff files.
#Acquire landsat scenes
outdir="C:/Users/Admin/Desktop/Programming/R_project"
setwd(outdir)
L8_2018 <- paste0(outdir,"/download/landsatdata/LC08_2018")
L8_2019 <- paste0(outdir,"/download/landsatdata/LC08_2019")
L8_2020 <- paste0(outdir,"/download/landsatdata/LC08_2020")
#check if files are missing
file.exists(L8_2018)
[1] TRUE
file.exists(L8_2019)
[1] TRUE
file.exists(L8_2020)
[1] TRUE
Making separate lists for every year 2018 - 2020
#save the file lists
productfiles2018 <- list.files(L8_2018, full.names = TRUE)
productfiles2019 <- list.files(L8_2019, full.names = TRUE)
productfiles2020 <- list.files(L8_2020, full.names = TRUE)
Preprocessing the tiff files into raster stacks for every year including only band 1 to band 7
#write a function for extract all 7 bands from landsat-8 scenes
grepBands <- function(files) {
bands <- c(grep('_band[1-7]{1}.tif', files, value=TRUE),
#grep('_band2.tif', files, value=TRUE),
#grep('_band3.tif', files, value=TRUE),
#grep('_band4.tif', files, value=TRUE),
#grep('_band5.tif', files, value=TRUE),
#grep('_band6.tif', files, value=TRUE),
#grep('_band7.tif', files, value=TRUE),
grep('_B[1-7]{1}.TIF', files, value=TRUE)
)
return(bands)
}
#extract the bands
bands2018 <- grepBands(productfiles2018)
bands2019 <- grepBands(productfiles2019)
bands2020 <- grepBands(productfiles2020)
#check if the greps were successful
if (exists("bands2018") == FALSE ||
exists("bands2019") == FALSE ||
exists("bands2020") == FALSE){
warning("Bands objects not found!")
} else if ((length(bands2018) == 7 & length(bands2019) == 7 & length(bands2020) == 7)) {
print("The bands are all there! Good to go!")
} else {
print("There are bands missing!")
}
[1] "The bands are all there! Good to go!"
#put them into raster stacks
stack2018 <- stack(bands2018)
stack2019 <- stack(bands2019)
stack2020 <- stack(bands2020)
Task 2: Calculate NDVI and NDWI
Explore the raster stacks including checking the layers, coordinate systems and resolution
#number of layers
nlayers(stack2018)
[1] 7
#nlayers(stack2019)
#nlayers(stack2020)
#coordinate systems
crs(stack2018)
CRS arguments:
+proj=utm +zone=21 +datum=WGS84 +units=m +no_defs
#crs(stack2019)
#crs(stack2020)
#resolution
res(stack2018)
[1] 30 30
#res(stack2019)
#res(stack2020)
Visualization of the RGB true composite image for every year
#print out the true color composites with the plotRGB function
#2018
par(col.axis="white",col.lab="white",tck=0)
plotRGB(stack2018, r = 4, g = 3, b = 2, axes = TRUE,
stretch = "lin", main = "True Color Composite 2018") #plot rgb image
box(col="white") #layout
#2019
par(col.axis="white",col.lab="white",tck=0)

plotRGB(stack2019, r = 4, g = 3, b = 2, axes = TRUE,
stretch = "lin", main = "True Color Composite 2019")
box(col="white")
#2020
par(col.axis="white",col.lab="white",tck=0)

plotRGB(stack2020, r = 4, g = 3, b = 2, axes = TRUE,
stretch = "lin", main = "True Color Composite 2020")
box(col="white")

Write the function for calculating NDVI and NDWI for the identification of the deforested areas from the Landsat-8 scenes
#write function for calculating NDVI
ndvi <- function(image) {
NDVI <- (image[[5]] - image[[4]])/(image[[5]] + image[[4]]) #normalized function using red and near-infrared (NIR)
return(NDVI) #return result
}
#write function for calculating NDWI
ndwi <- function(image) {
NDWI <- (image[[3]] - image[[5]])/(image[[3]] + image[[5]]) #normalized function using green and near-infrared (NIR)
return(NDWI) #return result
}
Crop Extent
Crop the full Landsat-8 scenes into the deforested regions
#set up the region of interest
roi <- as(extent(-57.451389,-57.1525,-7.275556,-6.966111), 'SpatialPolygons')
#define the coordinate system of the coordinates: lat and lon
crs(roi)="+proj=longlat +datum=WGS84"
#transform coordinates to UTM
roi.UTM <- spTransform(roi, crs(stack2018))
roi.UTM
#crop the stack image into the extent of roi
img2018_roi <- crop(stack2018, roi.UTM)
img2019_roi <- crop(stack2019, roi.UTM)
img2020_roi <- crop(stack2020, roi.UTM)
Create folder for output
if (pic_save == TRUE) { #if the parameter is true, set a folder for output
subDir <- "figureOutput"
ifelse(!dir.exists(file.path(outdir, subDir)), dir.create(file.path(outdir, subDir)), FALSE)
}
Remove unneeded variables
rm(L8_2018,L8_2019,L8_2020,outdir,productfiles2018,productfiles2019,productfiles2020)
rm(roi,roi.UTM,stack2018,stack2019,stack2020,bands2018,bands2019,bands2020)
Calculate Spectral Indexes
Apply NDVI and NDWI functions to the raster stacks
#calculate NDVI
ndvi2018 <- ndvi(img2018_roi)
ndvi2019 <- ndvi(img2019_roi)
ndvi2020 <- ndvi(img2020_roi)
#calculate differences of NDVI between years
dndvi_18_19 <- overlay(ndvi2019,
ndvi2018,
fun=function(r1, r2){return(r2-r1)})
dndvi_19_20 <- overlay(ndvi2020,
ndvi2019,
fun=function(r1, r2){return(r2-r1)}) #define function for overlay
#calculate NDWI
ndwi2018 <- ndwi(img2018_roi)
ndwi2019 <- ndwi(img2019_roi)
ndwi2020 <- ndwi(img2020_roi)
Transform the raster into dataframe for plotting NDWI using ggplot.
memory.limit(size=50000) #increased the allowed memory for the plotting
[1] 50000
#write a NDWI plotting function for all years
ndwi_plot <- function(lyr){
as(lyr,"SpatialPixelsDataFrame") %>% #pipe data frame into ggplot
as.data.frame() %>%
ggplot(data = .) +
geom_tile(aes(x = x, y = y, fill = layer)) +
theme(axis.text = element_blank(), #define custom layout
axis.ticks = element_blank(),
panel.background = element_blank(),
panel.grid.minor = element_blank()) +
labs(title = paste("NDWI ", substr(deparse(substitute(lyr)), nchar( deparse(substitute(lyr)))-4+1,nchar(deparse(substitute(lyr))))), #labels
x = " ",
y = " ") +
scale_fill_gradient2(high = "#0020FF", #custom coloring
mid = "#00FFBD",
low = "#533300",
midpoint = -0.2,
name = "NDWI")
}
p_ndwi18 <- ndwi_plot(ndwi2018)
p_ndwi19 <- ndwi_plot(ndwi2019)
p_ndwi20 <- ndwi_plot(ndwi2020)
p_ndwi <- p_ndwi18 + p_ndwi19 + p_ndwi20 + plot_layout(ncol = 2)#using all plots as subplots with the patchwork package
p_ndwi

if (pic_save == TRUE) { #save the output
ggsave(path = paste0(outdir,"/figureOutput"), "NDWI.png", scale=1.5, dpi=300)
}
From the NDWI, we can see the deforested area has a value around -0.2, sparsely vegetated area has values around -0.4 while the complete forest has lower values around -0.8. Although the mining area had already been established in the earlier image, some changes can be seen in the more recent image.
Same for plotting NDVI.
memory.limit(size=50000)
[1] 50000
ndvi_plot <- function(lyr){
as(lyr,"SpatialPixelsDataFrame") %>% #pipe data frame into ggplot
as.data.frame() %>%
ggplot(data = .) +
geom_tile(aes(x = x, y = y, fill = layer)) +
theme(axis.text = element_blank(), #define custom layout
axis.ticks = element_blank(),
panel.background = element_blank(),
panel.grid.minor = element_blank()) +
labs(title = paste("NDVI ", substr(deparse(substitute(lyr)), nchar( deparse(substitute(lyr)))-4+1,nchar(deparse(substitute(lyr))))), #labels
x = " ",
y = " ") +
scale_fill_gradient2(high = "#087F28", #color scheme for plotting
mid = "#CEE50E",
low = "#FF0000",
midpoint = 0.2,
name = "NDVI")
#scale_x_continuous(expand = c(0, 0)) +
#scale_y_continuous(expand = c(0, 0))
}
p_ndvi18 <- ndvi_plot(ndvi2018)
p_ndvi19 <- ndvi_plot(ndvi2019)
p_ndvi20 <- ndvi_plot(ndvi2020)
p_ndvi <- p_ndvi18 + p_ndvi19 + p_ndvi20 + plot_layout(ncol = 2)#combine all plots
p_ndvi

if (pic_save == TRUE) { #save the output
ggsave(path = paste0(outdir,"/figureOutput"), "NDVI.png", scale=1.5, dpi=300)
}
Just like NDWI, NDVI also shows similar patterns of deforested/mining area, which have significantly lower NDVI (~0.25) than the forest (>0.8). Next steps we will focus on the changes.
NDVI differences
Plot the changes of NDVI using ggplot to better visualize the temporal differences.
#Differences in NDVI between 2018 and 2020
p_dNDVI <- ggplot() +
geom_tile(data = as.data.frame(as(dndvi_18_19, "SpatialPixelsDataFrame")),
aes(x = x, y = y, fill = layer)) + #raster map for 18-19
scale_fill_gradient2(high = "#FBFF00",
mid = NA,
low = NA,
midpoint = 0,
limits = c(-0.2,0.2),
name = "19_20") +
new_scale_color() +
geom_tile(data = as.data.frame(as(dndvi_19_20, "SpatialPixelsDataFrame")), aes(x = x, y = y, fill = layer)) + #raster map for 19-20
scale_fill_gradient2(high = "#FF0000",
mid = NA,
low = NA,
midpoint = 0,
limits = c(-0.2,0.2),
name = "18_19") +
theme(axis.text = element_blank(), #layout
axis.ticks = element_blank(),
panel.background = element_blank(),
panel.grid.minor = element_blank(),
plot.title = element_text(hjust = 0.5)) +
labs(title = "NDVI Differences",
x = " ",
y = " ") +
dark_mode(theme_fivethirtyeight())
Scale for 'fill' is already present. Adding another scale for 'fill',
which will replace the existing scale.
p_dNDVI

if (pic_save == TRUE) { #save the output
ggsave(path = paste0(outdir,"/figureOutput"), "dNDVI.png", scale=1.5, dpi=300)
}
From the dNDVI image, we can see the development of deforestation between 2018 and 2020: Red stripes represent deforestation between 2018 and 2019, and yellow stripes represent deforestation between 2019 and 2020. They seem largely overlapped without zooming in. Apparently, changes are mostly going on at the edges of the already deforested area. To look better into the details, we can add a interactive base map in the background using the leaflet package.
#leaflet map
leaflet() %>% addProviderTiles(providers$Esri.WorldImagery) %>%
setView(-57.272078, -7.173734, zoom = 14) %>%
addRasterImage(dndvi_18_19, colors = "YlGnBu", opacity = 0.75, group = "Year18_19") %>%
addRasterImage(dndvi_19_20, colors = "YlOrRd", opacity = 0.75, group = "Year19_20") %>%
addLayersControl(
baseGroups = c("Esri"),
overlayGroups = c("Year18_19", "Year19_20"),
options = layersControlOptions(collapsed = FALSE))
Discarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definition
Task 3: Analyze Mining Development (2018 - 2020)
From the leaflet map we can clearly see the high correlation between recently deforested area and the already cleared area. The stripes appear to be extended in different branches compared to the earlier image.
- Change Vector Analysis (CVA)
Change detection using both magnitude and direction and plot the results. There are different changes comparing two images, however, part of the “changes” do not refers to deforestation, but caused by the cloud cover. To better distinguish the differences between recent deforestation and cloud cover, we can use CVA to observe are there differences between their angle of changes. Assuming the relationship between NDVI and NDWI is distinctive for cloud cover and deforestation, we input the stacked image of NDVI and NDWI for 2019 and 2020.
#CVA
cva_18_20 <- rasterCVA(stack(img2018_roi[[5]],img2018_roi[[4]]),stack(img2020_roi[[5]],img2020_roi[[4]]))
#Plot results
plot(cva_18_20)

if (pic_save == TRUE) { #save the output
ggsave(path = paste0(outdir,"/figureOutput"), "changeVectorAnalysis.png", scale=1.5, dpi=300)
}
From the CVA results, we can see the deforested area has a specific changing angles around 300-360 degrees, shown in green color in the left image. Meanwhile, we can see quite some noise in the forest with relatively small changing angles, which is arguably not representing deforestation/ glod mining.
#view deforested CVA in leaflet
leaflet() %>% addProviderTiles(providers$Esri.WorldImagery) %>%
setView(-57.272078, -7.173734, zoom = 14) %>%
addRasterImage(cva_18_20[[1]], colors = "YlOrRd", opacity = 0.55) #add raster results to an interactive map
Discarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crsDiscarded datum World Geodetic System 1984 in CRS definition
- GLCM Analysis To better understand the characteristics of deforested area, we can also do GLCM analysis to investigate the spatial patterns using glcm package.
#2020
glcm <- glcm(ndvi2020, window = c(9,9), shift = c(1,1),
statistics = c("mean", "variance", "homogeneity", "contrast",
"dissimilarity"))
plot(glcm)

if (pic_save == TRUE) { #save the output
ggsave(path = paste0(outdir,"/figureOutput"), "GLCM.png", scale=1.5, dpi=300)
}
From the GLCM analysis we can see the deforested area can be distinguish from different elements such as variance, homogeneity and dissimilarity. For example, the dissimilarity reveals the large difference of texture within the group. We can also calculate tasseled cap to check out the spatial patterns.
#2019 scene
tc_2019 <- tasseledCap(img2019_roi[[c(2:7)]], sat = "Landsat8OLI")
plot(tc_2019)

if (pic_save == TRUE) { #save the output
ggsave(path = paste0(outdir,"/figureOutput"), "tc_2019.png", scale=1.5, dpi=300)
}
#2020 scene
tc_2020 <- tasseledCap(img2020_roi[[c(2:7)]], sat = "Landsat8OLI")
plot(tc_2020)

if (pic_save == TRUE) { #save the output
ggsave(path = paste0(outdir,"/figureOutput"), "tc_2020.png", scale=1.5, dpi=300)
}
In the Tasseled Cap analysis, the most useful element for deforestation seems to be greenness which reveals clear patterns of the mining and deforestation development. Despite the mining pools in the gold mine, the wetness of the deforested area seems to be lower.
Task 4: Classify Forest Disturbance using Sentinel-1 and rgee Package
We can also investigate the deforestation process using Sentinel-1 images. As downloading and preprocessing radar images are computationally expensive, Google Earth Engine (GEE) offers R user another user-friendly option to work with Sentinel-1 images. In this project, backscatter values from Sentinel-1 level level-1 GRD images are analyzed for the region of interest.
Install, initialize and open Google Earth Engine (GEE)
Set up.
#ee_install()
ee_Initialize()
4/1AY0e-g5PQRWay0ZwMOo5xQmZOlv7mJP7q5QBxYRfytUxcLayDf5KF0dd5FE
ee_check()
ee_clean_credentials()
ee_clean_pyenv()
ee_search_dataset() %>% #search for data
ee_search_title("Sentinel-1 SAR GRD") %>% #look for sentinel-1
ee_search_display() #display search results
Define ROI
Define coordinates of the polygon for query.
roi_ee <- ee$Geometry$Polygon(
list(
c(-57.45139, -7.275556),
c(-57.45139, -6.966111),
c(-57.1525, -6.966111),
c(-57.1525, -7.275556))
)
Collect images
Acquire VV polarized Sentinel-1 images for the date ranges.
imgVV <- ee$ImageCollection('COPERNICUS/S1_GRD')$ #collect S1 data
filter(ee$Filter$listContains('transmitterReceiverPolarisation','VV'))$
filter(ee$Filter$eq('instrumentMode', 'IW'))$
filter(ee$Filter$eq('orbitProperties_pass', 'DESCENDING'))$
select('VV')
#2018
S1_2018 <- imgVV$
filterDate('2018-01-01' ,'2018-12-31')$ #filter dates
filterBounds(roi_ee)$ #set boundary
mean()$ #get mean values
clip(roi_ee) #clip the images
#2019
S1_2019 <- imgVV$
filterDate('2019-01-01' ,'2019-12-31')$
filterBounds(roi_ee)$
mean()$
clip(roi_ee)
#2020
S1_2020 <- imgVV$
filterDate('2020-01-01' ,'2020-12-31')$
filterBounds(roi_ee)$
mean()$
clip(roi_ee)
Speckle Filtering
Preprocess acquired Sentinel-1 images to reduce salt-and-pepper noise.
kernel <- ee$Kernel$circle((radius = 3)) #define kernel
filtered_2018 <- S1_2018$focal_mean(kernel = kernel, iterations = 1) #using mean filter for smoothing
filtered_2019 <- S1_2019$focal_mean(kernel = kernel, iterations = 1)
filtered_2020 <- S1_2020$focal_mean(kernel = kernel, iterations = 1)
Map$addLayer(filtered_2020, list(min = c(-30), max = c(30)), "filtered_2020") #display the filtered results in map
Map$centerObject(roi_ee, 12) #set center of display
Detection Forest Disturbance
Apply threshold for the identification of disturbed forest area and mask out the area.
threshold <- -9 #define threshold for detect disturbed forest based on pixel value inquiry
#filter data below threshold
area_2018 <- filtered_2018$lt(threshold)$rename("disturbed_area")
area_2019 <- filtered_2019$lt(threshold)$rename("disturbed_area")
area_2020 <- filtered_2020$lt(threshold)$rename("disturbed_area")
Map$addLayer(area_2018, {}, "forestDisturbance_2018") #display map
Map$addLayer(area_2019, {}, "forestDisturbance_2019")
Map$addLayer(area_2020, {}, "forestDisturbance_2020")
We can compared the data with Esri.WorldImagery basemap. Although the deforested area is not as visible as in the optical images, deforested areas show generally lower back scatter values. Besides, the radar data also reveals information about structure of the forest: low back scatter value prevail in changed forest structure compared to the base map. Nevertheless, more investigation need to be done for the details of changes it represents.
Development of Deforestation
Differentiate the disturbed forest area for the subsequent years.
#define area disturbed between 2018 and 2019
disturbed_18_19 <- (filtered_2018$gte(threshold))$
And(filtered_2019$lt(threshold))$
rename("disturbed_area_18_19")
#define area disturbed between 2019 and 2020
disturbed_19_20 <- filtered_2019$gte(threshold)$
And(filtered_2020$lt(threshold))$
rename("disturbed_area_19_20")
Map$addLayer(disturbed_18_19, {}, 'Disturbance between 2018 and 2019') #display map to visualize temporal changes
Map$addLayer(disturbed_19_20, {}, 'Disturbance between 2019 and 2020')
NA
If we differentiate not only the low backscatter values, but also the changes of low back scatter values, we can get insights about the mining development and get rid of other unneeded signals.
LS0tDQp0aXRsZTogIk1CMSBJbnRyb2R1Y3Rpb24gdG8gUHJvZ3JhbW1pbmcgKFdTIDIwMjAvMjEpIg0Kc3VidGl0bGU6ICdTZW1lc3RlciBQcm9qZWN0OiBUZW1wb3JhbCBEeW5hbWljcyBvZiBHb2xkIE1pbmluZyBpbiBNdW5kdXJ1a3UgKFBhcsOhKSBJbmRpZ2Vub3VzIFJlc2VydmVzJw0KYXV0aG9yOg0KICAtIEthIEhlaSBDaG93DQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiAlWScpYCINCnRhZ3M6IFtFQUdMRSwgUl0NCmFic3RyYWN0OiB8DQogIERlc3BpdGUgdGhlIGN1cnJlbnQgY2xpbWF0ZSBjcmlzaXMgaGFzIGFkZHJlc3NlZCB0aGUgZGVzdHJ1Y3RpdmUgZGVmb3Jlc3RhdGlvbiBpbiB0aGUgQW1hem9uLCB0aGUgd29ybGQncyBsYXJnZXN0IHJhaW5mb3Jlc3Qgd2hpY2ggaG9zdHMgaW1tZW5zZSBiaW9kaXZlcnNpdHksIGl0cyBkZWZvcmVzdGF0aW9uIHJhdGUgaGFkIHJhcGlkbHkgc3VyZ2VkIGluIHRoZSBwYXN0IHllYXJzLCBhcmd1Ymx5IGR1ZSB0byB0aGUgQm9sc29uYXJvJ3MgcmVnaW1lIGluIEJyYXppbC4gQWx0aG91Z2ggaW5kaWdlbm91cyB0ZXJyaXRvcnkgaXMgcHJvdGVjdGVkIGZyb20gZGV2ZWxvcG1lbnQsIGlsbGVnYWwgbWluaW5nIHByZXZhaWxzIGFuZCBleHBvc2VzIGluZGlnZW5vdXMgcGVvcGxlIHRvIGNsZWFyZWQgbGFuZCwgZGFtYWdlZCBlY29zeXN0ZW0gYW5kIGNvbXRhaW1pbmF0ZWQgd2F0ZXIuDQoNCiAgVGhpcyBwcm9qZWN0IGZvY3VzZXMgb24gTXVuZHVydWt1IEluZGlnZW5vdXMgUmVzZXJ2ZXMgKC03LjE3MzczNCwgLTU3LjI3MjA3OCkgbG9jYXRlZCBpbiB0aGUgUGFyw6Egc3RhdGUgb2YgQnJhemlsLiBJdCBhaW1zIHRvIGludmVzdGlnYXRlIHNwYXRpYWwgcGF0dGVybnMgb2YgdGhlIHJlY2VudCBtaW5pbmcgYW5kIGRlZm9yZXN0YXRpb24gaW4gdGhlIHJlZ2lvbiwgYXMgd2VsbCBhcyB0byBzaG93IHRoZSB1bmRlcmx5aW5nIGlzc3VlcyBvZiBnbG9iYWwgZm9yZXN0IGNoYW5nZXMgdXNpbmcgaW50ZXJhY3RpdmUgZGF0YSB2aXN1YWxpemF0aW9uLiBUaGUgdGFza3MgaW4gdGhpcyBwcm9qZWN0IGluY2x1ZGU6DQogIA0KICBhKSBMYW5kc2F0LTggKFBhdGg6IDIyODsgUm93OiAwNjUpIFByZXByb2Nlc3Npbmc7DQogIA0KICBiKSBDYWxjdWxhdGlvbiBvZiBTcGVjdHJhbCBJbmRleGVzIGFuZCBpZGVudGlmaWNhdGlvbiBvZiByZWNlbnQgZGVmb3Jlc3RhdGlvbjsNCiAgDQogIGMpIFN0YXRpc3RpY2FsIEFuYWx5c2lzIG9mIHNwZWN0cmFsIGluZm9ybWF0aW9uIGFuZCBDaGFuZ2UgVmVjdG9yIEFuYWx5c2lzOw0KICANCiAgZCkgSWRlbnRpZmljYXRpb24gb2YgRm9yZXN0IERpc3R1cmJhbmNlIGZyb20gU2VudGluZWwtMSB1c2luZyByZ2VlOw0KICANCiAgZSkgU2hpbnkgQXBwIGZvciBpbnRlcmFjdGl2ZWx5IG1hcHBpbmcgR2xvYmFsIEZvcmVzdCBDaGFuZ2VzDQogIA0KZ2VvbWV0cnk6IG1hcmdpbj0xaW4NCmZvbnRmYW1pbHk6IG1hdGhwYXpvDQpmb250c2l6ZTogMTZwdA0Kc3BhY2luZzogc2luZ2xlDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmZpZ19jYXB0aW9uOiB5ZXMNCi0tLQ0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpUaGlzIGlzIHRoZSBNQjEgc2VtZXN0ZXIgW1IgUHJvamVjdF0oaHR0cHM6Ly9naXRodWIuY29tL3Bpbmt5Y2hvdzEwMTAvTUIxX1Byb2dyYW1taW5nKS4gDQoNCkZpZy4gTWFwIHNob3dpbmcgdGhlIG1pbmluZyBvcGVyYXRpb24gd2l0aCBpbiB0aGUgaW5kaWdlbm91cyByZXNlcnZlLCB3aGljaCBpcyB0aGUgc3R1ZHkgc2l0ZSBvZiB0aGlzIFIgcHJvamVjdC4gDQohW10oQzovVXNlcnMvQWRtaW4vRGVza3RvcC9Qcm9ncmFtbWluZy9tYXAuanBnKQ0KDQoqKkxvYWRpbmcgbGlicmFyaWVzKioNCg0KSW5zdGFsbGluZyBhbmQgbG9hZGluZyBSIGxpYnJhcmllcyBmb3IgdGhlIGZvbGxvd2luZyBwcm9jZXNzaW5nIGFuZCB2aXN1YWxpemF0aW9uLg0KYGBge3IgZWNobyA9IFQsIHJlc3VsdHMgPSAnaGlkZScsIGVycm9yPUZBTFNFLCB3YXJuaW5ncz1GQUxTRX0NCmlmKCFyZXF1aXJlKGRldnRvb2xzKSkgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCmlmKCFyZXF1aXJlKHBhdGNod29yaykpIGluc3RhbGwucGFja2FnZXMoInBhdGNod29yayIsIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQ0KaWYoIXJlcXVpcmUoc3ApKSBpbnN0YWxsLnBhY2thZ2VzKCJzcCIsIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQ0KaWYoIXJlcXVpcmUoc2YpKSBpbnN0YWxsLnBhY2thZ2VzKCJzZiIsIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQ0KaWYoIXJlcXVpcmUocmdkYWwpKSBpbnN0YWxsLnBhY2thZ2VzKCJyZ2RhbCIsIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQ0KaWYoIXJlcXVpcmUoZ2dwbG90MikpIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCmlmKCFyZXF1aXJlKHJlc2hhcGUyKSkgaW5zdGFsbC5wYWNrYWdlcygicmVzaGFwZTIiLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCmlmKCFyZXF1aXJlKGRhdGEudGFibGUpKSBpbnN0YWxsLnBhY2thZ2VzKCJkYXRhLnRhYmxlIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQppZighcmVxdWlyZShnZ3RoZW1lcykpIGluc3RhbGwucGFja2FnZXMoImdndGhlbWVzIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQppZighcmVxdWlyZShnZ2RhcmspKSBpbnN0YWxsLnBhY2thZ2VzKCJnZ2RhcmsiLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCmlmKCFyZXF1aXJlKGdnbmV3c2NhbGUpKSBpbnN0YWxsLnBhY2thZ2VzKCJnZ25ld3NjYWxlIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQppZighcmVxdWlyZSh0aWR5dmVyc2UpKSBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCmlmKCFyZXF1aXJlKHJhc3RlclZpcykpIGluc3RhbGwucGFja2FnZXMoInJhc3RlclZpcyIsIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQ0KaWYoIXJlcXVpcmUobWFwdmlldykpIGluc3RhbGwucGFja2FnZXMoIm1hcHZpZXciLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCmlmKCFyZXF1aXJlKFJTdG9vbGJveCkpIGluc3RhbGwucGFja2FnZXMoIlJTdG9vbGJveCIsIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQ0KaWYoIXJlcXVpcmUoZ2xjbSkpIGluc3RhbGwucGFja2FnZXMoImdsY20iLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCmlmKCFyZXF1aXJlKHJnZWUpKSBpbnN0YWxsLnBhY2thZ2VzKCJyZ2VlIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQppZighcmVxdWlyZShsZWFmbGV0KSkgaW5zdGFsbC5wYWNrYWdlcygibGVhZmxldCIsIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQ0KaWYoIXJlcXVpcmUoZHBseXIpKSBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIsIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQ0KYGBgDQoNClVzZXItZGVmaW5lZCBwYXJhbWV0ZXINCmBgYHtyIGVjaG8gPSBULCByZXN1bHRzID0gJ2hpZGUnfQ0KcGljX3NhdmUgPSBGQUxTRSAjVFJVRSAjcGxlYXNlIGNoYW5nZSB0aGUgcGFyYW1ldGVyIHRvIFRSVUUgaWYgb3V0cHV0cyB3aXNoZWQgdG8gYmUgZG93bmxvYWRlZA0KYGBgDQoNCiMjICoqVGFzayAxOiBMYW5kc2F0IDggc2NlbmUgcHJlLXByb2Nlc3NpbmcqKg0KDQpMYW5kc2F0IDggc2NlbmVzIGF0IHRoZSByZWdpb24gb2YgaW50ZXJlc3QgaGF2ZSBiZWVuIGRvd25sb2FkZWQgZnJvbSBVU0dTLiBIZXJlIHdlIHNldCB1cCB0aGUgZGlyZWN0b3J5IGFuZCBjaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0aWZmIGZpbGVzLg0KYGBge3IgZXJyb3I9RkFMU0UsIHdhcm5pbmdzPUZBTFNFfQ0KI0FjcXVpcmUgbGFuZHNhdCBzY2VuZXMNCm91dGRpcj0iQzovVXNlcnMvQWRtaW4vRGVza3RvcC9Qcm9ncmFtbWluZy9SX3Byb2plY3QiDQpzZXR3ZChvdXRkaXIpDQoNCkw4XzIwMTggPC0gcGFzdGUwKG91dGRpciwiL2Rvd25sb2FkL2xhbmRzYXRkYXRhL0xDMDhfMjAxOCIpDQpMOF8yMDE5IDwtIHBhc3RlMChvdXRkaXIsIi9kb3dubG9hZC9sYW5kc2F0ZGF0YS9MQzA4XzIwMTkiKQ0KTDhfMjAyMCA8LSBwYXN0ZTAob3V0ZGlyLCIvZG93bmxvYWQvbGFuZHNhdGRhdGEvTEMwOF8yMDIwIikNCg0KI2NoZWNrIGlmIGZpbGVzIGFyZSBtaXNzaW5nDQpmaWxlLmV4aXN0cyhMOF8yMDE4KQ0KZmlsZS5leGlzdHMoTDhfMjAxOSkNCmZpbGUuZXhpc3RzKEw4XzIwMjApDQpgYGANCk1ha2luZyBzZXBhcmF0ZSBsaXN0cyBmb3IgZXZlcnkgeWVhciAyMDE4IC0gMjAyMA0KYGBge3IgZXJyb3I9RkFMU0UsIHdhcm5pbmdzPUZBTFNFfQ0KI3NhdmUgdGhlIGZpbGUgbGlzdHMNCnByb2R1Y3RmaWxlczIwMTggPC0gbGlzdC5maWxlcyhMOF8yMDE4LCBmdWxsLm5hbWVzID0gVFJVRSkNCnByb2R1Y3RmaWxlczIwMTkgPC0gbGlzdC5maWxlcyhMOF8yMDE5LCBmdWxsLm5hbWVzID0gVFJVRSkNCnByb2R1Y3RmaWxlczIwMjAgPC0gbGlzdC5maWxlcyhMOF8yMDIwLCBmdWxsLm5hbWVzID0gVFJVRSkNCmBgYA0KDQpQcmVwcm9jZXNzaW5nIHRoZSB0aWZmIGZpbGVzIGludG8gcmFzdGVyIHN0YWNrcyBmb3IgZXZlcnkgeWVhciBpbmNsdWRpbmcgb25seSBiYW5kIDEgdG8gYmFuZCA3DQpgYGB7ciBlcnJvcj1GQUxTRSwgd2FybmluZ3M9RkFMU0V9DQojd3JpdGUgYSBmdW5jdGlvbiBmb3IgZXh0cmFjdCBhbGwgNyBiYW5kcyBmcm9tIGxhbmRzYXQtOCBzY2VuZXMNCmdyZXBCYW5kcyA8LSBmdW5jdGlvbihmaWxlcykgew0KICBiYW5kcyA8LSBjKGdyZXAoJ19iYW5kWzEtN117MX0udGlmJywgZmlsZXMsIHZhbHVlPVRSVUUpLA0KICAgICAgICAgICBncmVwKCdfQlsxLTddezF9LlRJRicsIGZpbGVzLCB2YWx1ZT1UUlVFKQ0KICAgICAgICAgICApDQogIHJldHVybihiYW5kcykgI3JldHVybiB0aGUgbmFtZXMgb2YgdGhlIGZpbGVzDQp9DQoNCiNleHRyYWN0IHRoZSBiYW5kcw0KYmFuZHMyMDE4IDwtIGdyZXBCYW5kcyhwcm9kdWN0ZmlsZXMyMDE4KSAjYXBwbHkgZnVuY3Rpb24gdG8gZWFjaCB5ZWFyDQpiYW5kczIwMTkgPC0gZ3JlcEJhbmRzKHByb2R1Y3RmaWxlczIwMTkpDQpiYW5kczIwMjAgPC0gZ3JlcEJhbmRzKHByb2R1Y3RmaWxlczIwMjApDQogIA0KI2NoZWNrIGlmIHRoZSBncmVwcyB3ZXJlIHN1Y2Nlc3NmdWw6DQojdGhpcyBjb2RlIGdpdmUgdGhlIHN0YXR1cyBvZiB0aGUgYmFuZHMgZXh0cmFjdGlvbiAtIGV4cGVjdGVkOiBHb29kIHRvIGdvIG1lc3NhZ2UuDQppZiAoZXhpc3RzKCJiYW5kczIwMTgiKSA9PSBGQUxTRSB8fCANCiAgICBleGlzdHMoImJhbmRzMjAxOSIpID09IEZBTFNFIHx8IA0KICAgIGV4aXN0cygiYmFuZHMyMDIwIikgPT0gRkFMU0Upew0Kd2FybmluZygiQmFuZHMgb2JqZWN0cyBub3QgZm91bmQhIikNCn0gZWxzZSBpZiAoKGxlbmd0aChiYW5kczIwMTgpID09IDcgJiBsZW5ndGgoYmFuZHMyMDE5KSA9PSA3ICYgbGVuZ3RoKGJhbmRzMjAyMCkgPT0gNykpIHsNCnByaW50KCJUaGUgYmFuZHMgYXJlIGFsbCB0aGVyZSEgR29vZCB0byBnbyEiKQ0KfSBlbHNlIHsNCiAgICBwcmludCgiVGhlcmUgYXJlIGJhbmRzIG1pc3NpbmchIikNCn0NCg0KI3B1dCB0aGUgYmFuZHMgaW4gdGhlIGxpc3RzIGludG8gcmFzdGVyIHN0YWNrIG9iamVjdHMNCnN0YWNrMjAxOCA8LSBzdGFjayhiYW5kczIwMTgpDQpzdGFjazIwMTkgPC0gc3RhY2soYmFuZHMyMDE5KQ0Kc3RhY2syMDIwIDwtIHN0YWNrKGJhbmRzMjAyMCkNCmBgYA0KDQojIyAqKlRhc2sgMjogQ2FsY3VsYXRlIE5EVkkgYW5kIE5EV0kqKg0KDQpFeHBsb3JlIHRoZSByYXN0ZXIgc3RhY2tzIGluY2x1ZGluZyBjaGVja2luZyB0aGUgbGF5ZXJzLCBjb29yZGluYXRlIHN5c3RlbXMgYW5kIHJlc29sdXRpb24NCmBgYHtyIGVycm9yPUZBTFNFLCB3YXJuaW5ncz1GQUxTRX0NCiNudW1iZXIgb2YgbGF5ZXJzDQpubGF5ZXJzKHN0YWNrMjAxOCkNCiNubGF5ZXJzKHN0YWNrMjAxOSkNCiNubGF5ZXJzKHN0YWNrMjAyMCkNCg0KI2Nvb3JkaW5hdGUgc3lzdGVtcw0KY3JzKHN0YWNrMjAxOCkNCiNjcnMoc3RhY2syMDE5KQ0KI2NycyhzdGFjazIwMjApDQoNCiNyZXNvbHV0aW9uDQpyZXMoc3RhY2syMDE4KQ0KI3JlcyhzdGFjazIwMTkpDQojcmVzKHN0YWNrMjAyMCkNCmBgYA0KDQpWaXN1YWxpemF0aW9uIG9mIHRoZSBSR0IgdHJ1ZSBjb21wb3NpdGUgaW1hZ2UgZm9yIGV2ZXJ5IHllYXINCmBgYHtyIGVycm9yPUZBTFNFLCB3YXJuaW5ncz1GQUxTRX0NCiNwcmludCBvdXQgdGhlIHRydWUgY29sb3IgY29tcG9zaXRlcyB3aXRoIHRoZSBwbG90UkdCIGZ1bmN0aW9uDQojMjAxOA0KcGFyKGNvbC5heGlzPSJ3aGl0ZSIsY29sLmxhYj0id2hpdGUiLHRjaz0wKQ0KcGxvdFJHQihzdGFjazIwMTgsIHIgPSA0LCBnID0gMywgYiA9IDIsIGF4ZXMgPSBUUlVFLCANCiAgICAgICAgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIlRydWUgQ29sb3IgQ29tcG9zaXRlIDIwMTgiKSAjcGxvdCByZ2IgaW1hZ2UNCmJveChjb2w9IndoaXRlIikgI2xheW91dA0KDQojMjAxOQ0KcGFyKGNvbC5heGlzPSJ3aGl0ZSIsY29sLmxhYj0id2hpdGUiLHRjaz0wKQ0KcGxvdFJHQihzdGFjazIwMTksIHIgPSA0LCBnID0gMywgYiA9IDIsIGF4ZXMgPSBUUlVFLCANCiAgICAgICAgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIlRydWUgQ29sb3IgQ29tcG9zaXRlIDIwMTkiKQ0KYm94KGNvbD0id2hpdGUiKQ0KDQojMjAyMA0KcGFyKGNvbC5heGlzPSJ3aGl0ZSIsY29sLmxhYj0id2hpdGUiLHRjaz0wKQ0KcGxvdFJHQihzdGFjazIwMjAsIHIgPSA0LCBnID0gMywgYiA9IDIsIGF4ZXMgPSBUUlVFLCANCiAgICAgICAgc3RyZXRjaCA9ICJsaW4iLCBtYWluID0gIlRydWUgQ29sb3IgQ29tcG9zaXRlIDIwMjAiKQ0KYm94KGNvbD0id2hpdGUiKQ0KYGBgDQoNCldyaXRlIHRoZSBmdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgTkRWSSBhbmQgTkRXSSBmb3IgdGhlIGlkZW50aWZpY2F0aW9uIG9mIHRoZSBkZWZvcmVzdGVkIGFyZWFzIGZyb20gdGhlIExhbmRzYXQtOCBzY2VuZXMNCmBgYHtyIGVycm9yPUZBTFNFLCB3YXJuaW5ncz1GQUxTRX0NCiN3cml0ZSBmdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgTkRWSQ0KbmR2aSA8LSBmdW5jdGlvbihpbWFnZSkgew0KICBORFZJIDwtIChpbWFnZVtbNV1dIC0gaW1hZ2VbWzRdXSkvKGltYWdlW1s1XV0gKyBpbWFnZVtbNF1dKSAjbm9ybWFsaXplZCBmdW5jdGlvbiB1c2luZyByZWQgYW5kIG5lYXItaW5mcmFyZWQgKE5JUikNCiAgcmV0dXJuKE5EVkkpICNyZXR1cm4gcmVzdWx0DQp9DQoNCiN3cml0ZSBmdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgTkRXSQ0KbmR3aSA8LSBmdW5jdGlvbihpbWFnZSkgew0KICBORFdJIDwtIChpbWFnZVtbM11dIC0gaW1hZ2VbWzVdXSkvKGltYWdlW1szXV0gKyBpbWFnZVtbNV1dKSAjbm9ybWFsaXplZCBmdW5jdGlvbiB1c2luZyBncmVlbiBhbmQgbmVhci1pbmZyYXJlZCAoTklSKQ0KICByZXR1cm4oTkRXSSkgI3JldHVybiByZXN1bHQNCn0NCmBgYA0KDQoqKkNyb3AgRXh0ZW50KioNCg0KQ3JvcCB0aGUgZnVsbCBMYW5kc2F0LTggc2NlbmVzIGludG8gdGhlIGRlZm9yZXN0ZWQgcmVnaW9ucw0KYGBge3IgZWNobyA9IFQsIHJlc3VsdHMgPSAnaGlkZScsIGVycm9yPUZBTFNFLCB3YXJuaW5ncz1GQUxTRX0NCiNzZXQgdXAgdGhlIHJlZ2lvbiBvZiBpbnRlcmVzdA0Kcm9pIDwtIGFzKGV4dGVudCgtNTcuNDUxMzg5LC01Ny4xNTI1LC03LjI3NTU1NiwtNi45NjYxMTEpLCAnU3BhdGlhbFBvbHlnb25zJykNCg0KI2RlZmluZSB0aGUgY29vcmRpbmF0ZSBzeXN0ZW0gb2YgdGhlIGNvb3JkaW5hdGVzOiBsYXQgYW5kIGxvbg0KY3JzKHJvaSk9Iitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0Ig0KDQojdHJhbnNmb3JtIGNvb3JkaW5hdGVzIG9mIG91ciBkZWZpbmVkIHJlZ2lvbiB0byBVVE0NCnJvaS5VVE0gPC0gc3BUcmFuc2Zvcm0ocm9pLCBjcnMoc3RhY2syMDE4KSkNCnJvaS5VVE0NCg0KI2Nyb3AgdGhlIHN0YWNrIGltYWdlIGludG8gdGhlIGV4dGVudCBvZiByb2kNCmltZzIwMThfcm9pIDwtIGNyb3Aoc3RhY2syMDE4LCByb2kuVVRNKQ0KaW1nMjAxOV9yb2kgPC0gY3JvcChzdGFjazIwMTksIHJvaS5VVE0pDQppbWcyMDIwX3JvaSA8LSBjcm9wKHN0YWNrMjAyMCwgcm9pLlVUTSkgI3RoZSBwcmVwcm9jZXNzZWQgcHJvZHVjdHMgZm9yIHRoZSBhbmFseXNpcw0KYGBgDQoNCkNyZWF0ZSBmb2xkZXIgZm9yIG91dHB1dA0KYGBge3J9DQppZiAocGljX3NhdmUgPT0gVFJVRSkgeyAjaWYgdGhlIHBhcmFtZXRlciBpcyB0cnVlLCBzZXQgYSBmb2xkZXIgZm9yIG91dHB1dA0KICBzdWJEaXIgPC0gImZpZ3VyZU91dHB1dCIgI25hbWUgb2YgdGhlIGZvbGRlcg0KICBpZmVsc2UoIWRpci5leGlzdHMoZmlsZS5wYXRoKG91dGRpciwgc3ViRGlyKSksIGRpci5jcmVhdGUoZmlsZS5wYXRoKG91dGRpciwgc3ViRGlyKSksIEZBTFNFKSAjb25seSBjcmVhdGUgZm9sZGVyIGlmIHRoZSBmb2xkZXIgZG9lcyBub3QgZXhpc3RzDQp9DQpgYGANCg0KUmVtb3ZlIHVubmVlZGVkIHZhcmlhYmxlcw0KYGBge3J9DQpybShMOF8yMDE4LEw4XzIwMTksTDhfMjAyMCxvdXRkaXIscHJvZHVjdGZpbGVzMjAxOCxwcm9kdWN0ZmlsZXMyMDE5LHByb2R1Y3RmaWxlczIwMjApDQoNCnJtKHJvaSxyb2kuVVRNLHN0YWNrMjAxOCxzdGFjazIwMTksc3RhY2syMDIwLGJhbmRzMjAxOCxiYW5kczIwMTksYmFuZHMyMDIwKQ0KYGBgDQoNCioqQ2FsY3VsYXRlIFNwZWN0cmFsIEluZGV4ZXMqKg0KDQpBcHBseSBORFZJIGFuZCBORFdJIGZ1bmN0aW9ucyB0byB0aGUgcmFzdGVyIHN0YWNrcw0KYGBge3IgZXJyb3I9RkFMU0UsIHdhcm5pbmdzPUZBTFNFfQ0KI2NhbGN1bGF0ZSBORFZJDQpuZHZpMjAxOCA8LSBuZHZpKGltZzIwMThfcm9pKSAjYXBwbHkgbmR2aSBmdW5jdGlvbiB0byBlYWNoIHllYXINCm5kdmkyMDE5IDwtIG5kdmkoaW1nMjAxOV9yb2kpDQpuZHZpMjAyMCA8LSBuZHZpKGltZzIwMjBfcm9pKQ0KDQojY2FsY3VsYXRlIGRpZmZlcmVuY2VzIG9mIE5EVkkgYmV0d2VlbiB5ZWFycw0KZG5kdmlfMThfMTkgPC0gb3ZlcmxheShuZHZpMjAxOSwNCiAgICAgICAgICAgICAgICAgICAgICBuZHZpMjAxOCwNCiAgICAgICAgICAgICAgICAgICAgICBmdW49ZnVuY3Rpb24ocjEsIHIyKXtyZXR1cm4ocjItcjEpfSkgI2RlZmluZSBmdW5jdGlvbiBmb3Igb3ZlcmxheQ0KDQpkbmR2aV8xOV8yMCA8LSBvdmVybGF5KG5kdmkyMDIwLA0KICAgICAgICAgICAgICAgICAgICAgIG5kdmkyMDE5LA0KICAgICAgICAgICAgICAgICAgICAgIGZ1bj1mdW5jdGlvbihyMSwgcjIpe3JldHVybihyMi1yMSl9KQ0KDQojY2FsY3VsYXRlIE5EV0kNCm5kd2kyMDE4IDwtIG5kd2koaW1nMjAxOF9yb2kpICNhcHBseSBuZHdpIGZ1bmN0aW9uIHRvIGVhY2ggeWVhcg0KbmR3aTIwMTkgPC0gbmR3aShpbWcyMDE5X3JvaSkNCm5kd2kyMDIwIDwtIG5kd2koaW1nMjAyMF9yb2kpDQpgYGANCg0KIC0gKipQbG90IE5EV0kgZm9yIDIwMjAqKg0KIA0KVHJhbnNmb3JtIHRoZSByYXN0ZXIgaW50byBkYXRhZnJhbWUgZm9yIHBsb3R0aW5nIE5EV0kgdXNpbmcgZ2dwbG90Lg0KYGBge3IgZXJyb3I9RkFMU0UsIHdhcm5pbmdzPUZBTFNFfQ0KbWVtb3J5LmxpbWl0KHNpemU9NTAwMDApICNpbmNyZWFzZWQgdGhlIGFsbG93ZWQgbWVtb3J5IGZvciB0aGUgcGxvdHRpbmcNCg0KI3dyaXRlIGEgTkRXSSBwbG90dGluZyBmdW5jdGlvbiBmb3IgYWxsIHllYXJzDQpuZHdpX3Bsb3QgPC0gZnVuY3Rpb24obHlyKXsNCiAgYXMobHlyLCJTcGF0aWFsUGl4ZWxzRGF0YUZyYW1lIikgJT4lICNwaXBlIGRhdGEgZnJhbWUgaW50byBnZ3Bsb3QNCiAgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICBnZ3Bsb3QoZGF0YSA9IC4pICsNCiAgZ2VvbV90aWxlKGFlcyh4ID0geCwgeSA9IHksIGZpbGwgPSBsYXllcikpICsgI3Jhc3RlciBtYXANCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCAjZGVmaW5lIGN1c3RvbSBsYXlvdXQNCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHRpdGxlID0gcGFzdGUoIk5EV0kgIiwgc3Vic3RyKGRlcGFyc2Uoc3Vic3RpdHV0ZShseXIpKSwgbmNoYXIoIGRlcGFyc2Uoc3Vic3RpdHV0ZShseXIpKSktNCsxLG5jaGFyKGRlcGFyc2Uoc3Vic3RpdHV0ZShseXIpKSkpKSwgICNsYWJlbHMgYXJlIGV4dHJhY3RlZCBmcm9tIHRoZSBuYW1lcyBvZiB0aGUgdmFyaWFibGVzDQogICAgICAgeCA9ICIgIiwgDQogICAgICAgeSA9ICIgIikgKyANCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIoaGlnaCA9ICIjMDAyMEZGIiwgI2N1c3RvbSBjb2xvcmluZw0KICAgICAgICAgICAgICAgICAgICAgIG1pZCA9ICIjMDBGRkJEIiwNCiAgICAgICAgICAgICAgICAgICAgICBsb3cgPSAiIzUzMzMwMCIsDQogICAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSAtMC4yLA0KICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiTkRXSSIpDQp9DQoNCnBfbmR3aTE4IDwtIG5kd2lfcGxvdChuZHdpMjAxOCkgI2FwcGx5IHRoZSBwbG90IGZ1bmN0aW9uIHRvIGVhY2ggeWVhcg0KcF9uZHdpMTkgPC0gbmR3aV9wbG90KG5kd2kyMDE5KQ0KcF9uZHdpMjAgPC0gbmR3aV9wbG90KG5kd2kyMDIwKQ0KDQpwX25kd2kgPC0gcF9uZHdpMTggKyBwX25kd2kxOSArIHBfbmR3aTIwICsgIHBsb3RfbGF5b3V0KG5jb2wgPSAyKSN1c2luZyBhbGwgcGxvdHMgYXMgc3VicGxvdHMgd2l0aCB0aGUgcGF0Y2h3b3JrIHBhY2thZ2Ugd2l0aCBkZWZpbmVkIGxheW91dA0KcF9uZHdpDQoNCmlmIChwaWNfc2F2ZSA9PSBUUlVFKSB7ICNzYXZlIHRoZSBvdXRwdXQNCmdnc2F2ZShwYXRoID0gcGFzdGUwKG91dGRpciwiL2ZpZ3VyZU91dHB1dCIpLCAiTkRXSS5wbmciLCBzY2FsZT0xLjUsIGRwaT0zMDApDQp9DQpgYGANCkZyb20gdGhlIE5EV0ksIHdlIGNhbiBzZWUgdGhlIGRlZm9yZXN0ZWQgYXJlYSBoYXMgYSB2YWx1ZSBhcm91bmQgLTAuMiwgc3BhcnNlbHkgdmVnZXRhdGVkIGFyZWEgaGFzIHZhbHVlcyBhcm91bmQgLTAuNCB3aGlsZSB0aGUgY29tcGxldGUgZm9yZXN0IGhhcyBsb3dlciB2YWx1ZXMgYXJvdW5kIC0wLjguIEFsdGhvdWdoIHRoZSBtaW5pbmcgYXJlYSBoYWQgYWxyZWFkeSBiZWVuIGVzdGFibGlzaGVkIGluIHRoZSBlYXJsaWVyIGltYWdlLCBzb21lIGNoYW5nZXMgY2FuIGJlIHNlZW4gaW4gdGhlIG1vcmUgcmVjZW50IGltYWdlLg0KDQogLSAqKlBsb3QgTkRWSSoqDQogDQpTYW1lIGZvciBwbG90dGluZyBORFZJLg0KYGBge3IgZXJyb3I9RkFMU0UsIHdhcm5pbmdzPUZBTFNFfQ0KbWVtb3J5LmxpbWl0KHNpemU9NTAwMDApDQoNCiNkZWZpbmUgYW5vdGhlciBmdW5jdGlvbiB3aXRoIGRpZmZlcmVudCBsYXlvdXQgZm9yIHBsb3R0aW5nIG5kdmkNCm5kdmlfcGxvdCA8LSBmdW5jdGlvbihseXIpew0KICBhcyhseXIsIlNwYXRpYWxQaXhlbHNEYXRhRnJhbWUiKSAlPiUgI3BpcGUgZGF0YSBmcmFtZSBpbnRvIGdncGxvdA0KICBhcy5kYXRhLmZyYW1lKCkgJT4lDQogIGdncGxvdChkYXRhID0gLikgKw0KICBnZW9tX3RpbGUoYWVzKHggPSB4LCB5ID0geSwgZmlsbCA9IGxheWVyKSkgKw0KICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksICNkZWZpbmUgY3VzdG9tIGxheW91dA0KICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnModGl0bGUgPSBwYXN0ZSgiTkRWSSAiLCBzdWJzdHIoZGVwYXJzZShzdWJzdGl0dXRlKGx5cikpLCBuY2hhciggZGVwYXJzZShzdWJzdGl0dXRlKGx5cikpKS00KzEsbmNoYXIoZGVwYXJzZShzdWJzdGl0dXRlKGx5cikpKSkpLCAgI2xhYmVscw0KICAgICAgIHggPSAiICIsIA0KICAgICAgIHkgPSAiICIpICsgDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGhpZ2ggPSAiIzA4N0YyOCIsICNjb2xvciBzY2hlbWUgZm9yIHBsb3R0aW5nDQogICAgICAgICAgICAgICAgICAgICAgbWlkID0gIiNDRUU1MEUiLA0KICAgICAgICAgICAgICAgICAgICAgIGxvdyA9ICIjRkYwMDAwIiwNCiAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAuMiwNCiAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIk5EVkkiKQ0KfQ0KDQpwX25kdmkxOCA8LSBuZHZpX3Bsb3QobmR2aTIwMTgpICNhcHBseSBkZWZpbmVkIGZ1bmN0aW9uDQpwX25kdmkxOSA8LSBuZHZpX3Bsb3QobmR2aTIwMTkpDQpwX25kdmkyMCA8LSBuZHZpX3Bsb3QobmR2aTIwMjApDQoNCnBfbmR2aSA8LSBwX25kdmkxOCArIHBfbmR2aTE5ICsgcF9uZHZpMjAgKyBwbG90X2xheW91dChuY29sID0gMikjY29tYmluZSBhbGwgcGxvdHMNCnBfbmR2aQ0KDQppZiAocGljX3NhdmUgPT0gVFJVRSkgeyAjc2F2ZSB0aGUgb3V0cHV0DQpnZ3NhdmUocGF0aCA9IHBhc3RlMChvdXRkaXIsIi9maWd1cmVPdXRwdXQiKSwgIk5EVkkucG5nIiwgc2NhbGU9MS41LCBkcGk9MzAwKQ0KfQ0KYGBgDQpKdXN0IGxpa2UgTkRXSSwgTkRWSSBhbHNvIHNob3dzIHNpbWlsYXIgcGF0dGVybnMgb2YgZGVmb3Jlc3RlZC9taW5pbmcgYXJlYSwgd2hpY2ggaGF2ZSBzaWduaWZpY2FudGx5IGxvd2VyIE5EVkkgKH4wLjI1KSB0aGFuIHRoZSBmb3Jlc3QgKD4wLjgpLiBOZXh0IHN0ZXBzIHdlIHdpbGwgZm9jdXMgb24gdGhlIGNoYW5nZXMuIA0KDQoqKk5EVkkgZGlmZmVyZW5jZXMqKg0KDQpQbG90IHRoZSBjaGFuZ2VzIG9mIE5EVkkgdXNpbmcgZ2dwbG90IHRvIGJldHRlciB2aXN1YWxpemUgdGhlIHRlbXBvcmFsIGRpZmZlcmVuY2VzLiANCmBgYHtyIGVycm9yPUZBTFNFLCB3YXJuaW5ncz1GQUxTRX0NCiNEaWZmZXJlbmNlcyBpbiBORFZJIGJldHdlZW4gMjAxOCBhbmQgMjAyMA0KcF9kTkRWSSA8LSBnZ3Bsb3QoKSArIA0KICBnZW9tX3RpbGUoZGF0YSA9IGFzLmRhdGEuZnJhbWUoYXMoZG5kdmlfMThfMTksICJTcGF0aWFsUGl4ZWxzRGF0YUZyYW1lIikpLCANCiAgICAgICAgICAgIGFlcyh4ID0geCwgeSA9IHksIGZpbGwgPSBsYXllcikpICsgI3Jhc3RlciBtYXAgZm9yIDE4LTE5DQogICAgc2NhbGVfZmlsbF9ncmFkaWVudDIoaGlnaCA9ICIjRkJGRjAwIiwgI2NvbG9yaW5nIGZvciAxOC0xOQ0KICAgICAgICAgICAgICAgICAgICAgIG1pZCA9IE5BLA0KICAgICAgICAgICAgICAgICAgICAgIGxvdyA9IE5BLA0KICAgICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gMCwNCiAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0wLjIsMC4yKSwNCiAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIjE4XzE5IikgKyANCiAgICBuZXdfc2NhbGVfY29sb3IoKSArICNmcm9tIGdnbmV3c2NhbGUgcGFja2FnZSBmb3IgbXVsdGlwbGUgY29sb3Igc2NhbGUNCiAgICBnZW9tX3RpbGUoZGF0YSA9IGFzLmRhdGEuZnJhbWUoYXMoZG5kdmlfMTlfMjAsICJTcGF0aWFsUGl4ZWxzRGF0YUZyYW1lIikpLCBhZXMoeCA9IHgsIHkgPSB5LCBmaWxsID0gbGF5ZXIpKSArICNyYXN0ZXIgbWFwIGZvciAxOS0yMA0KICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGhpZ2ggPSAiI0ZGMDAwMCIsICNuZXcgY29sb3Igc2NhbGUgZm9yIDE5LTIwDQogICAgICAgICAgICAgICAgICAgICAgbWlkID0gTkEsDQogICAgICAgICAgICAgICAgICAgICAgbG93ID0gTkEsDQogICAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoLTAuMiwwLjIpLA0KICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiMTlfMjAiKSArIA0KICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksICNsYXlvdXQNCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgbGFicyh0aXRsZSA9ICJORFZJIERpZmZlcmVuY2VzIiwgI3Bsb3QgdGl0bGUNCiAgICAgICB4ID0gIiAiLCANCiAgICAgICB5ID0gIiAiKSArIA0KICBkYXJrX21vZGUodGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkpICNnZ3RoZW1lDQoNCnBfZE5EVkkNCg0KaWYgKHBpY19zYXZlID09IFRSVUUpIHsgI3NhdmUgdGhlIG91dHB1dA0KZ2dzYXZlKHBhdGggPSBwYXN0ZTAob3V0ZGlyLCIvZmlndXJlT3V0cHV0IiksICJkTkRWSS5wbmciLCBzY2FsZT0xLjUsIGRwaT0zMDApDQp9DQpgYGANCkZyb20gdGhlIGRORFZJIGltYWdlLCB3ZSBjYW4gc2VlIHRoZSBkZXZlbG9wbWVudCBvZiBkZWZvcmVzdGF0aW9uIGJldHdlZW4gMjAxOCBhbmQgMjAyMDogUmVkIHN0cmlwZXMgcmVwcmVzZW50IGRlZm9yZXN0YXRpb24gYmV0d2VlbiAyMDE4IGFuZCAyMDE5LCBhbmQgeWVsbG93IHN0cmlwZXMgcmVwcmVzZW50IGRlZm9yZXN0YXRpb24gYmV0d2VlbiAyMDE5IGFuZCAyMDIwLiBUaGV5IHNlZW0gbGFyZ2VseSBvdmVybGFwcGVkIHdpdGhvdXQgem9vbWluZyBpbi4gQXBwYXJlbnRseSwgY2hhbmdlcyBhcmUgbW9zdGx5IGdvaW5nIG9uIGF0IHRoZSBlZGdlcyBvZiB0aGUgYWxyZWFkeSBkZWZvcmVzdGVkIGFyZWEuIFRvIGxvb2sgYmV0dGVyIGludG8gdGhlIGRldGFpbHMsIHdlIGNhbiBhZGQgYSBpbnRlcmFjdGl2ZSBiYXNlIG1hcCBpbiB0aGUgYmFja2dyb3VuZCB1c2luZyB0aGUgbGVhZmxldCBwYWNrYWdlLg0KDQpgYGB7cn0NCiNsZWFmbGV0IG1hcA0KbGVhZmxldCgpICU+JSBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRFc3JpLldvcmxkSW1hZ2VyeSkgJT4lICNiYXNlIG1hcA0KICBzZXRWaWV3KC01Ny4yNzIwNzgsIC03LjE3MzczNCwgem9vbSA9IDE0KSAlPiUgI3NldCBjZW50cmUNCiAgYWRkUmFzdGVySW1hZ2UoZG5kdmlfMThfMTksIGNvbG9ycyA9ICJZbEduQnUiLCBvcGFjaXR5ID0gMC43NSwgZ3JvdXAgPSAiWWVhcjE4XzE5IikgJT4lICNmaXJzdCBtYXANCiAgYWRkUmFzdGVySW1hZ2UoZG5kdmlfMTlfMjAsIGNvbG9ycyA9ICJZbE9yUmQiLCBvcGFjaXR5ID0gMC43NSwgZ3JvdXAgPSAiWWVhcjE5XzIwIikgJT4lICNzZWNvbmQgbWFwDQogIGFkZExheWVyc0NvbnRyb2woICNsYXllciBjb250cm9sIHRvIGFsbG93IHVzZXIgc3dpdGNoIGluZGl2aWR1YWwgbWFwcyBvbiBhbmQgb2ZmDQogICAgYmFzZUdyb3VwcyA9IGMoIkVzcmkiKSwNCiAgICBvdmVybGF5R3JvdXBzID0gYygiWWVhcjE4XzE5IiwgIlllYXIxOV8yMCIpLCAjZ3JvdXBzIG9mIHNlbGVjdGlvbg0KICAgIG9wdGlvbnMgPSBsYXllcnNDb250cm9sT3B0aW9ucyhjb2xsYXBzZWQgPSBGQUxTRSkpDQoNCmBgYA0KDQojIyAqKlRhc2sgMzogQW5hbHl6ZSBNaW5pbmcgRGV2ZWxvcG1lbnQgKDIwMTggLSAyMDIwKSoqDQoNCiBGcm9tIHRoZSBsZWFmbGV0IG1hcCB3ZSBjYW4gY2xlYXJseSBzZWUgdGhlIGhpZ2ggY29ycmVsYXRpb24gYmV0d2VlbiByZWNlbnRseSBkZWZvcmVzdGVkIGFyZWEgYW5kIHRoZSBhbHJlYWR5IGNsZWFyZWQgYXJlYS4gVGhlIHN0cmlwZXMgYXBwZWFyIHRvIGJlIGV4dGVuZGVkIGluIGRpZmZlcmVudCBicmFuY2hlcyBjb21wYXJlZCB0byB0aGUgZWFybGllciBpbWFnZS4gDQogDQogLSAqKkNoYW5nZSBWZWN0b3IgQW5hbHlzaXMgKENWQSkqKg0KIA0KQ2hhbmdlIGRldGVjdGlvbiB1c2luZyBib3RoIG1hZ25pdHVkZSBhbmQgZGlyZWN0aW9uIGFuZCBwbG90IHRoZSByZXN1bHRzLiBUaGVyZSBhcmUgZGlmZmVyZW50IGNoYW5nZXMgY29tcGFyaW5nIHR3byBpbWFnZXMsIGhvd2V2ZXIsIHBhcnQgb2YgdGhlICJjaGFuZ2VzIiBkbyBub3QgcmVmZXJzIHRvIGRlZm9yZXN0YXRpb24sIGJ1dCBjYXVzZWQgYnkgdGhlIGNsb3VkIGNvdmVyLiBUbyBiZXR0ZXIgZGlzdGluZ3Vpc2ggdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gcmVjZW50IGRlZm9yZXN0YXRpb24gYW5kIGNsb3VkIGNvdmVyLCB3ZSBjYW4gdXNlIENWQSB0byBvYnNlcnZlIGFyZSB0aGVyZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZWlyIGFuZ2xlIG9mIGNoYW5nZXMuIEFzc3VtaW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBORFZJIGFuZCBORFdJIGlzIGRpc3RpbmN0aXZlIGZvciBjbG91ZCBjb3ZlciBhbmQgZGVmb3Jlc3RhdGlvbiwgd2UgaW5wdXQgdGhlIHN0YWNrZWQgaW1hZ2Ugb2YgTkRWSSBhbmQgTkRXSSBmb3IgMjAxOSBhbmQgMjAyMC4NCmBgYHtyIGVycm9yPUZBTFNFLCB3YXJuaW5ncz1GQUxTRX0NCiNDVkEgKHJlZCBhbmQgTklSIGJhbmRzIG9mIGxhbmRzYXQtOCkgYmV0d2VlbiAyMDE4IGFuZCAyMDIwDQpjdmFfMThfMjAgPC0gcmFzdGVyQ1ZBKHN0YWNrKGltZzIwMThfcm9pW1s1XV0saW1nMjAxOF9yb2lbWzRdXSksc3RhY2soaW1nMjAyMF9yb2lbWzVdXSxpbWcyMDIwX3JvaVtbNF1dKSkNCg0KI1Bsb3QgcmVzdWx0cw0KcGxvdChjdmFfMThfMjApDQoNCmlmIChwaWNfc2F2ZSA9PSBUUlVFKSB7ICNzYXZlIHRoZSBvdXRwdXQNCmdnc2F2ZShwYXRoID0gcGFzdGUwKG91dGRpciwiL2ZpZ3VyZU91dHB1dCIpLCAiY2hhbmdlVmVjdG9yQW5hbHlzaXMucG5nIiwgc2NhbGU9MS41LCBkcGk9MzAwKQ0KfQ0KYGBgDQpGcm9tIHRoZSBDVkEgcmVzdWx0cywgd2UgY2FuIHNlZSB0aGUgZGVmb3Jlc3RlZCBhcmVhIGhhcyBhIHNwZWNpZmljIGNoYW5naW5nIGFuZ2xlcyBhcm91bmQgMzAwLTM2MCBkZWdyZWVzLCBzaG93biBpbiBncmVlbiBjb2xvciBpbiB0aGUgbGVmdCBpbWFnZS4gTWVhbndoaWxlLCB3ZSBjYW4gc2VlIHF1aXRlIHNvbWUgbm9pc2UgaW4gdGhlIGZvcmVzdCB3aXRoIHJlbGF0aXZlbHkgc21hbGwgY2hhbmdpbmcgYW5nbGVzLCB3aGljaCBpcyBhcmd1YWJseSBub3QgcmVwcmVzZW50aW5nIGRlZm9yZXN0YXRpb24vIGdsb2QgbWluaW5nLg0KDQpgYGB7cn0NCiN2aWV3IGRlZm9yZXN0ZWQgQ1ZBIGluIGxlYWZsZXQNCmxlYWZsZXQoKSAlPiUgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkRXNyaS5Xb3JsZEltYWdlcnkpICU+JSANCiAgc2V0VmlldygtNTcuMjcyMDc4LCAtNy4xNzM3MzQsIHpvb20gPSAxNCkgJT4lIA0KICBhZGRSYXN0ZXJJbWFnZShjdmFfMThfMjBbWzFdXSwgY29sb3JzID0gIllsT3JSZCIsIG9wYWNpdHkgPSAwLjU1KSAjYWRkIHJhc3RlciByZXN1bHRzIHRvIGFuIGludGVyYWN0aXZlIG1hcA0KYGBgDQogDQogIC0gKipHTENNIEFuYWx5c2lzKioNCiAgVG8gYmV0dGVyIHVuZGVyc3RhbmQgdGhlIGNoYXJhY3RlcmlzdGljcyBvZiBkZWZvcmVzdGVkIGFyZWEsIHdlIGNhbiBhbHNvIGRvIEdMQ00gYW5hbHlzaXMgdG8gaW52ZXN0aWdhdGUgdGhlIHNwYXRpYWwgcGF0dGVybnMgdXNpbmcgZ2xjbSBwYWNrYWdlLg0KYGBge3IgZXJyb3I9RkFMU0UsIHdhcm5pbmdzPUZBTFNFfQ0KIzIwMjANCmdsY20gPC0gZ2xjbShuZHZpMjAyMCwgd2luZG93ID0gYyg5LDkpLCBzaGlmdCA9IGMoMSwxKSwgDQogICAgICAgICAgICAgIHN0YXRpc3RpY3MgPSBjKCJtZWFuIiwgInZhcmlhbmNlIiwgImhvbW9nZW5laXR5IiwgImNvbnRyYXN0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkaXNzaW1pbGFyaXR5IikpICNzZWxlY3Rpb24gb2Ygc3RhdGlzdGljYWwgcGFyYW1ldGVycw0KcGxvdChnbGNtKSAjc2hvdyByZXN1bHRzDQoNCmlmIChwaWNfc2F2ZSA9PSBUUlVFKSB7ICNzYXZlIHRoZSBvdXRwdXQNCmdnc2F2ZShwYXRoID0gcGFzdGUwKG91dGRpciwiL2ZpZ3VyZU91dHB1dCIpLCAiR0xDTS5wbmciLCBzY2FsZT0xLjUsIGRwaT0zMDApDQp9DQpgYGANCkZyb20gdGhlIEdMQ00gYW5hbHlzaXMgd2UgY2FuIHNlZSB0aGUgZGVmb3Jlc3RlZCBhcmVhIGNhbiBiZSBkaXN0aW5ndWlzaCBmcm9tIGRpZmZlcmVudCBlbGVtZW50cyBzdWNoIGFzIHZhcmlhbmNlLCBob21vZ2VuZWl0eSBhbmQgZGlzc2ltaWxhcml0eS4gRm9yIGV4YW1wbGUsIHRoZSBkaXNzaW1pbGFyaXR5IHJldmVhbHMgdGhlIGxhcmdlIGRpZmZlcmVuY2Ugb2YgdGV4dHVyZSB3aXRoaW4gdGhlIGdyb3VwLiBXZSBjYW4gYWxzbyBjYWxjdWxhdGUgdGFzc2VsZWQgY2FwIHRvIGNoZWNrIG91dCB0aGUgc3BhdGlhbCBwYXR0ZXJucy4NCiANCiAtICoqVGFzc2VsZWQgQ2FwIENhbGN1bGF0aW9uKioNCmBgYHtyIGVycm9yPUZBTFNFLCB3YXJuaW5ncz1GQUxTRX0NCiMyMDE4IHNjZW5lDQp0Y18yMDE4IDwtIHRhc3NlbGVkQ2FwKGltZzIwMThfcm9pW1tjKDI6NyldXSwgc2F0ID0gIkxhbmRzYXQ4T0xJIikgI2FkanVzdCBwYXJhbWV0ZXJzIHRvIGJlIGxhbmRzYXQtOCBzcGVjaWZpYw0KcGxvdCh0Y18yMDE4KQ0KDQppZiAocGljX3NhdmUgPT0gVFJVRSkgeyAjc2F2ZSB0aGUgb3V0cHV0DQpnZ3NhdmUocGF0aCA9IHBhc3RlMChvdXRkaXIsIi9maWd1cmVPdXRwdXQiKSwgInRjXzIwMTgucG5nIiwgc2NhbGU9MS41LCBkcGk9MzAwKQ0KfQ0KDQojMjAxOSBzY2VuZQ0KdGNfMjAxOSA8LSB0YXNzZWxlZENhcChpbWcyMDE5X3JvaVtbYygyOjcpXV0sIHNhdCA9ICJMYW5kc2F0OE9MSSIpDQpwbG90KHRjXzIwMTkpDQoNCmlmIChwaWNfc2F2ZSA9PSBUUlVFKSB7ICNzYXZlIHRoZSBvdXRwdXQNCmdnc2F2ZShwYXRoID0gcGFzdGUwKG91dGRpciwiL2ZpZ3VyZU91dHB1dCIpLCAidGNfMjAxOS5wbmciLCBzY2FsZT0xLjUsIGRwaT0zMDApDQp9DQoNCiMyMDIwIHNjZW5lDQp0Y18yMDIwIDwtIHRhc3NlbGVkQ2FwKGltZzIwMjBfcm9pW1tjKDI6NyldXSwgc2F0ID0gIkxhbmRzYXQ4T0xJIikNCnBsb3QodGNfMjAyMCkNCg0KaWYgKHBpY19zYXZlID09IFRSVUUpIHsgI3NhdmUgdGhlIG91dHB1dA0KZ2dzYXZlKHBhdGggPSBwYXN0ZTAob3V0ZGlyLCIvZmlndXJlT3V0cHV0IiksICJ0Y18yMDIwLnBuZyIsIHNjYWxlPTEuNSwgZHBpPTMwMCkNCn0NCmBgYA0KSW4gdGhlIFRhc3NlbGVkIENhcCBhbmFseXNpcywgdGhlIG1vc3QgdXNlZnVsIGVsZW1lbnQgZm9yIGRlZm9yZXN0YXRpb24gc2VlbXMgdG8gYmUgZ3JlZW5uZXNzIHdoaWNoIHJldmVhbHMgY2xlYXIgcGF0dGVybnMgb2YgdGhlIG1pbmluZyBhbmQgZGVmb3Jlc3RhdGlvbiBkZXZlbG9wbWVudC4gRGVzcGl0ZSB0aGUgbWluaW5nIHBvb2xzIGluIHRoZSBnb2xkIG1pbmUsIHRoZSB3ZXRuZXNzIG9mIHRoZSBkZWZvcmVzdGVkIGFyZWEgc2VlbXMgdG8gYmUgbG93ZXIuDQoNCiMjICoqVGFzayA0OiBDbGFzc2lmeSBGb3Jlc3QgRGlzdHVyYmFuY2UgdXNpbmcgU2VudGluZWwtMSBhbmQgcmdlZSBQYWNrYWdlKioNCldlIGNhbiBhbHNvIGludmVzdGlnYXRlIHRoZSBkZWZvcmVzdGF0aW9uIHByb2Nlc3MgdXNpbmcgU2VudGluZWwtMSBpbWFnZXMuIEFzIGRvd25sb2FkaW5nIGFuZCBwcmVwcm9jZXNzaW5nIHJhZGFyIGltYWdlcyBhcmUgY29tcHV0YXRpb25hbGx5IGV4cGVuc2l2ZSwgR29vZ2xlIEVhcnRoIEVuZ2luZSAoR0VFKSBvZmZlcnMgUiB1c2VyIGFub3RoZXIgdXNlci1mcmllbmRseSBvcHRpb24gdG8gd29yayB3aXRoIFNlbnRpbmVsLTEgaW1hZ2VzLiBJbiB0aGlzIHByb2plY3QsIGJhY2tzY2F0dGVyIHZhbHVlcyBmcm9tIFNlbnRpbmVsLTEgbGV2ZWwgbGV2ZWwtMSBHUkQgaW1hZ2VzIGFyZSBhbmFseXplZCBmb3IgdGhlIHJlZ2lvbiBvZiBpbnRlcmVzdC4NCg0KKipJbnN0YWxsLCBpbml0aWFsaXplIGFuZCBvcGVuIEdvb2dsZSBFYXJ0aCBFbmdpbmUgKEdFRSkqKg0KDQpTZXQgdXAuDQpgYGB7ciBlY2hvID0gVCwgcmVzdWx0cyA9ICdoaWRlJywgZXJyb3I9RkFMU0UsIHdhcm5pbmdzPUZBTFNFfQ0KI2VlX2luc3RhbGwoKQ0KZWVfSW5pdGlhbGl6ZSgpDQplZV9jaGVjaygpIA0KZWVfY2xlYW5fY3JlZGVudGlhbHMoKSANCmVlX2NsZWFuX3B5ZW52KCkgDQoNCmVlX3NlYXJjaF9kYXRhc2V0KCkgJT4lICNzZWFyY2ggZm9yIGRhdGENCiAgZWVfc2VhcmNoX3RpdGxlKCJTZW50aW5lbC0xIFNBUiBHUkQiKSAlPiUgI2xvb2sgZm9yIHNlbnRpbmVsLTENCiAgZWVfc2VhcmNoX2Rpc3BsYXkoKSAgICNkaXNwbGF5IHNlYXJjaCByZXN1bHRzDQoNCmBgYA0KDQoqKkRlZmluZSBST0kqKg0KDQpEZWZpbmUgY29vcmRpbmF0ZXMgb2YgdGhlIHBvbHlnb24gZm9yIHF1ZXJ5Lg0KYGBge3IgZXJyb3I9RkFMU0UsIHdhcm5pbmdzPUZBTFNFfQ0Kcm9pX2VlIDwtIGVlJEdlb21ldHJ5JFBvbHlnb24oDQogIGxpc3QoDQogICAgYygtNTcuNDUxMzksIC03LjI3NTU1NiksDQogICAgYygtNTcuNDUxMzksIC02Ljk2NjExMSksDQogICAgYygtNTcuMTUyNSwgLTYuOTY2MTExKSwNCiAgICBjKC01Ny4xNTI1LCAtNy4yNzU1NTYpKQ0KKQ0KYGBgDQoNCioqQ29sbGVjdCBpbWFnZXMqKg0KDQpBY3F1aXJlIFZWIHBvbGFyaXplZCBTZW50aW5lbC0xIGltYWdlcyBmb3IgdGhlIGRhdGUgcmFuZ2VzLg0KYGBge3IgZXJyb3I9RkFMU0UsIHdhcm5pbmdzPUZBTFNFfQ0KaW1nVlYgPC0gZWUkSW1hZ2VDb2xsZWN0aW9uKCdDT1BFUk5JQ1VTL1MxX0dSRCcpJCAjY29sbGVjdCBTMSBkYXRhDQogICAgICAgIGZpbHRlcihlZSRGaWx0ZXIkbGlzdENvbnRhaW5zKCd0cmFuc21pdHRlclJlY2VpdmVyUG9sYXJpc2F0aW9uJywnVlYnKSkkDQogICAgICAgIGZpbHRlcihlZSRGaWx0ZXIkZXEoJ2luc3RydW1lbnRNb2RlJywgJ0lXJykpJA0KICAgICAgICBmaWx0ZXIoZWUkRmlsdGVyJGVxKCdvcmJpdFByb3BlcnRpZXNfcGFzcycsICdERVNDRU5ESU5HJykpJA0KICAgICAgICBzZWxlY3QoJ1ZWJykNCg0KIzIwMTgNClMxXzIwMTggPC0gaW1nVlYkDQogIGZpbHRlckRhdGUoJzIwMTgtMDEtMDEnICwnMjAxOC0xMi0zMScpJCAjZmlsdGVyIGRhdGVzDQogIGZpbHRlckJvdW5kcyhyb2lfZWUpJCAjc2V0IGJvdW5kYXJ5DQogIG1lYW4oKSQgI2dldCBtZWFuIHZhbHVlcw0KICBjbGlwKHJvaV9lZSkgI2NsaXAgdGhlIGltYWdlcw0KDQojMjAxOQ0KUzFfMjAxOSA8LSBpbWdWViQNCiAgZmlsdGVyRGF0ZSgnMjAxOS0wMS0wMScgLCcyMDE5LTEyLTMxJykkDQogIGZpbHRlckJvdW5kcyhyb2lfZWUpJA0KICBtZWFuKCkkDQogIGNsaXAocm9pX2VlKQ0KDQojMjAyMA0KUzFfMjAyMCA8LSBpbWdWViQNCiAgZmlsdGVyRGF0ZSgnMjAyMC0wMS0wMScgLCcyMDIwLTEyLTMxJykkDQogIGZpbHRlckJvdW5kcyhyb2lfZWUpJA0KICBtZWFuKCkkDQogIGNsaXAocm9pX2VlKQ0KYGBgDQoNCioqU3BlY2tsZSBGaWx0ZXJpbmcqKg0KDQpQcmVwcm9jZXNzIGFjcXVpcmVkIFNlbnRpbmVsLTEgaW1hZ2VzIHRvIHJlZHVjZSBzYWx0LWFuZC1wZXBwZXIgbm9pc2UuDQpgYGB7ciBlcnJvcj1GQUxTRSwgd2FybmluZ3M9RkFMU0V9DQprZXJuZWwgPC0gZWUkS2VybmVsJGNpcmNsZSgocmFkaXVzID0gMykpICNkZWZpbmUga2VybmVsDQoNCmZpbHRlcmVkXzIwMTggPC0gIFMxXzIwMTgkZm9jYWxfbWVhbihrZXJuZWwgPSBrZXJuZWwsIGl0ZXJhdGlvbnMgPSAxKSAjdXNpbmcgbWVhbiBmaWx0ZXIgZm9yIHNtb290aGluZw0KZmlsdGVyZWRfMjAxOSA8LSAgUzFfMjAxOSRmb2NhbF9tZWFuKGtlcm5lbCA9IGtlcm5lbCwgaXRlcmF0aW9ucyA9IDEpDQpmaWx0ZXJlZF8yMDIwIDwtICBTMV8yMDIwJGZvY2FsX21lYW4oa2VybmVsID0ga2VybmVsLCBpdGVyYXRpb25zID0gMSkNCg0KTWFwJGFkZExheWVyKGZpbHRlcmVkXzIwMjAsIGxpc3QobWluID0gYygtMzApLCBtYXggPSBjKDMwKSksICJmaWx0ZXJlZF8yMDIwIikgI2Rpc3BsYXkgdGhlIGZpbHRlcmVkIHJlc3VsdHMgaW4gbWFwDQpNYXAkY2VudGVyT2JqZWN0KHJvaV9lZSwgMTIpICNzZXQgY2VudGVyIG9mIGRpc3BsYXkNCmBgYA0KDQoqKkRldGVjdGlvbiBGb3Jlc3QgRGlzdHVyYmFuY2UqKg0KDQpBcHBseSB0aHJlc2hvbGQgZm9yIHRoZSBpZGVudGlmaWNhdGlvbiBvZiBkaXN0dXJiZWQgZm9yZXN0IGFyZWEgYW5kIG1hc2sgb3V0IHRoZSBhcmVhLg0KYGBge3IgZXJyb3I9RkFMU0UsIHdhcm5pbmdzPUZBTFNFfQ0KdGhyZXNob2xkIDwtIC05ICNkZWZpbmUgdGhyZXNob2xkIGZvciBkZXRlY3QgZGlzdHVyYmVkIGZvcmVzdCBiYXNlZCBvbiBwaXhlbCB2YWx1ZSBpbnF1aXJ5DQoNCiNmaWx0ZXIgZGF0YSBiZWxvdyB0aHJlc2hvbGQNCmFyZWFfMjAxOCA8LSBmaWx0ZXJlZF8yMDE4JGx0KHRocmVzaG9sZCkkcmVuYW1lKCJkaXN0dXJiZWRfYXJlYSIpICNmaWx0ZXIgaW1hZ2UgdG8gaW5jbHVkZSBvbmx5IHBpeGVscyBiZWxvdyB0aHJlc2hvbGQ7IHJlbmFtZSBpdCB0byBkaXN0dXJiZWQgYXJlYQ0KYXJlYV8yMDE5IDwtIGZpbHRlcmVkXzIwMTkkbHQodGhyZXNob2xkKSRyZW5hbWUoImRpc3R1cmJlZF9hcmVhIikNCmFyZWFfMjAyMCA8LSBmaWx0ZXJlZF8yMDIwJGx0KHRocmVzaG9sZCkkcmVuYW1lKCJkaXN0dXJiZWRfYXJlYSIpDQoNCk1hcCRhZGRMYXllcihhcmVhXzIwMTgsIHt9LCAiZm9yZXN0RGlzdHVyYmFuY2VfMjAxOCIpICNkaXNwbGF5IG1hcA0KTWFwJGFkZExheWVyKGFyZWFfMjAxOSwge30sICJmb3Jlc3REaXN0dXJiYW5jZV8yMDE5IikNCk1hcCRhZGRMYXllcihhcmVhXzIwMjAsIHt9LCAiZm9yZXN0RGlzdHVyYmFuY2VfMjAyMCIpDQpgYGANCldlIGNhbiBjb21wYXJlZCB0aGUgZGF0YSB3aXRoIEVzcmkuV29ybGRJbWFnZXJ5IGJhc2VtYXAuIEFsdGhvdWdoIHRoZSBkZWZvcmVzdGVkIGFyZWEgaXMgbm90IGFzIHZpc2libGUgYXMgaW4gdGhlIG9wdGljYWwgaW1hZ2VzLCBkZWZvcmVzdGVkIGFyZWFzIHNob3cgZ2VuZXJhbGx5IGxvd2VyIGJhY2sgc2NhdHRlciB2YWx1ZXMuIEJlc2lkZXMsIHRoZSByYWRhciBkYXRhIGFsc28gcmV2ZWFscyBpbmZvcm1hdGlvbiBhYm91dCBzdHJ1Y3R1cmUgb2YgdGhlIGZvcmVzdDogbG93IGJhY2sgc2NhdHRlciB2YWx1ZSBwcmV2YWlsIGluIGNoYW5nZWQgZm9yZXN0IHN0cnVjdHVyZSBjb21wYXJlZCB0byB0aGUgYmFzZSBtYXAuIE5ldmVydGhlbGVzcywgbW9yZSBpbnZlc3RpZ2F0aW9uIG5lZWQgdG8gYmUgZG9uZSBmb3IgdGhlIGRldGFpbHMgb2YgY2hhbmdlcyBpdCByZXByZXNlbnRzLg0KDQoqKkRldmVsb3BtZW50IG9mIERlZm9yZXN0YXRpb24qKg0KDQpEaWZmZXJlbnRpYXRlIHRoZSBkaXN0dXJiZWQgZm9yZXN0IGFyZWEgZm9yIHRoZSBzdWJzZXF1ZW50IHllYXJzLg0KYGBge3IgZXJyb3I9RkFMU0UsIHdhcm5pbmdzPUZBTFNFfQ0KI2RlZmluZSBhcmVhIGRpc3R1cmJlZCBiZXR3ZWVuIDIwMTggYW5kIDIwMTkNCmRpc3R1cmJlZF8xOF8xOSA8LSAoZmlsdGVyZWRfMjAxOCRndGUodGhyZXNob2xkKSkkICNnZXQgdGhlIHBpeGVscyBvbmx5IGRyb3BwZWQgYmVsb3cgdGhyZXNob2xkIGJldHdlZW4gMjAxOCBhbmQgMjAxOQ0KICBBbmQoZmlsdGVyZWRfMjAxOSRsdCh0aHJlc2hvbGQpKSQNCiAgcmVuYW1lKCJkaXN0dXJiZWRfYXJlYV8xOF8xOSIpDQoNCiNkZWZpbmUgYXJlYSBkaXN0dXJiZWQgYmV0d2VlbiAyMDE5IGFuZCAyMDIwDQpkaXN0dXJiZWRfMTlfMjAgPC0gZmlsdGVyZWRfMjAxOSRndGUodGhyZXNob2xkKSQgI2dldCB0aGUgcGl4ZWxzIG9ubHkgZHJvcHBlZCBiZWxvdyB0aHJlc2hvbGQgYmV0d2VlbiAyMDE5IGFuZCAyMDIwDQogIEFuZChmaWx0ZXJlZF8yMDIwJGx0KHRocmVzaG9sZCkpJA0KICByZW5hbWUoImRpc3R1cmJlZF9hcmVhXzE5XzIwIikNCg0KTWFwJGFkZExheWVyKGRpc3R1cmJlZF8xOF8xOSwge30sICdEaXN0dXJiYW5jZSBiZXR3ZWVuIDIwMTggYW5kIDIwMTknKSAjZGlzcGxheSBtYXAgdG8gdmlzdWFsaXplIHRlbXBvcmFsIGNoYW5nZXMNCk1hcCRhZGRMYXllcihkaXN0dXJiZWRfMTlfMjAsIHt9LCAnRGlzdHVyYmFuY2UgYmV0d2VlbiAyMDE5IGFuZCAyMDIwJykNCg0KYGBgDQpJZiB3ZSBkaWZmZXJlbnRpYXRlIG5vdCBvbmx5IHRoZSBsb3cgYmFja3NjYXR0ZXIgdmFsdWVzLCBidXQgYWxzbyB0aGUgY2hhbmdlcyBvZiBsb3cgYmFjayBzY2F0dGVyIHZhbHVlcywgd2UgY2FuIGdldCBpbnNpZ2h0cyBhYm91dCB0aGUgbWluaW5nIGRldmVsb3BtZW50IGFuZCBnZXQgcmlkIG9mIG90aGVyIHVubmVlZGVkIHNpZ25hbHMuDQoNCiMjICoqVGFzayA1OiBDcmVhdGUgU2hpbnkgQXBwIGZvciB2aXN1YWxpemluZyBXb3JsZCBCYW5rIGZvcmVzdCBkYXRhKioNCg0KKiBQbGVhc2UgcmVmZXIgdG8gYXBwLlIgZm9yIHRoZSBzY3JpcHQgb2YgdGhlIFNoaW55IEFwcC4NCg0KVGhpcyBhcHAgY2FuIGJlIG9wZW5lZCBieSBjbGlja2luZyB0aGlzIGxpbms6DQpodHRwczovL2VhZ2xlLXJwcm9qZWN0LWdsb2JhbGZvcmVzdGNoYW5nZXMuc2hpbnlhcHBzLmlvL2dsb2JhbEZvcmVzdENoYW5nZXMvDQoNCg0KIyMgKipSZWZlcmVuY2U6KioNCg0KaHR0cHM6Ly9kYXRhLndvcmxkYmFuay5vcmcvaW5kaWNhdG9yL0FHLkxORC5GUlNULlpTDQoNCmh0dHBzOi8vbmV3cy5tb25nYWJheS5jb20vMjAyMC8xMi9pbGxlZ2FsLW1pbmluZy1zcGFya3MtbWFsYXJpYS1vdXRicmVhay1pbi1pbmRpZ2Vub3VzLXRlcnJpdG9yaWVzLWluLWJyYXppbC8NCiAgDQpodHRwczovL21hYXByb2plY3Qub3JnLzIwMjAvZ29sZF9icmF6aWwvDQogIA0KaHR0cHM6Ly9hbWF6b253YXRjaC5vcmcvYXNzZXRzL2ZpbGVzLzIwMjAtY29tcGxpY2l0eS1pbi1kZXN0cnVjdGlvbi0zLnBkZg0KICANCmh0dHBzOi8vbmV3cy5tb25nYWJheS5jb20vMjAyMC8wMS92YWxlLWhhcy1maWxlZC1odW5kcmVkcy1vZi1yZXF1ZXN0cy10by1leHBsb2l0LWluZGlnZW5vdXMtbGFuZHMtaW4tYW1hem9uLw0K